/*
 * Copyright (c) 2009, Hamish Morgan. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * 3. Neither the name of the University of Sussex nor the names of its
 *    contributors may be used to endorse or promote products derived from
 *    this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */
package locusts;

import java.io.IOException;
import java.util.Locale;
import java.util.ResourceBundle;
import locusts.client.Client;
import locusts.client.ClientConfig;
import locusts.client.ClientWindow;
import locusts.server.Game;
import locusts.server.GameFactory;
import locusts.server.Server;
import locusts.server.admin.LocustsAdmin;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Collection of static methods to be used to start the locusts application.
 * 
 * @author Hamish Morgan
 */
public final class Main {

    /**
     * String resources for i8n
     */
    private static final ResourceBundle strings = ResourceBundle.getBundle(
            "strings", Locale.getDefault());
    /**
     * The slf4j log output class.
     */
    private static final Logger LOG = LoggerFactory.getLogger(Main.class);
    /**
     * Defult port to use for client/server comms if no other is specified.
     */
    public static int DEFAULT_PORT = 32922;
    /**
     * Defult host to use for client/server comms if no other is specified.
     */
    public static String DEFAULT_HOST = "localhost";
    private static String START_MENU = "menu";
    private static String START_LOCAL = "local";
    private static String START_SERVER = "server";
    private static String START_ADMIN = "adminserver";
    private static String START_CLIENT = "client";
    private static String START_DEFAULT = START_MENU;

    /**
     * This class should not be instantiated because it contains only static
     * methods. Therefore the constructor has private scope.
     */
    private Main() {
        // Not a sausage
    }

    /**
     * The default main method, which passes command line arguments and
     * starts the locusts game.
     *
     * @param args  Command line arguments
     * @throws IOException  When opening network connections goes wrong.
     */
    public final static void main(final String[] args) throws IOException {

        final String start = (args.length == 0)
                ? START_DEFAULT
                : args[0].trim().toLowerCase();

        if (START_MENU.equals(start)) {

            startMenu();

        } else if (START_LOCAL.equals(start)) {

            final int port = getPort(args, 1);
            startLocal(port);

        } else if (START_SERVER.equals(start)) {

            final int port = getPort(args, 1);
            startServer(port);

        } else if (START_ADMIN.equals(start)) {

            final int port = getPort(args, 1);
            startAdminServer(port);

        } else if (START_CLIENT.equals(start)) {

            final String host = getHost(args, 1);
            final int port = getPort(args, 2);
            startClient(host, port);

        } else {

            System.out.println(strings.getString("INVALID_CMD_LINE_ARG"));
            System.out.println(strings.getString("app_usage"));
        }
    }

    /**
     * Read the port number from the command line arguments at the given index.
     *
     * @param args  The command line arguments
     * @param index The index that the port will be at.
     * @return  The port number.
     */
    private static final int getPort(final String[] args, final int index) {
        return (args.length <= index)
                ? Main.DEFAULT_PORT
                : Integer.parseInt(args[index]);
    }

    /**
     * Read the host name from the command line arguments at the given index.
     * 
     * @param args The command line arguments
     * @param index The index of the host in the arguments
     * @return  The host name
     */
    private static final String getHost(final String[] args, final int index) {
        return (args.length <= index)
                ? Main.DEFAULT_HOST
                : args[index];
    }

    /**
     * Show the main menu UI from where the user can decide how locsts
     * should be started.
     */
    public static final void startMenu() {
        new MainMenu().setVisible(true);
    }

    /**
     * Start a local server and connect a client to it. The given port will be
     * used if other clients want to connect to the local server.
     * 
     * @param port  
     * @throws IOException
     */
    public static final void startLocal(final int port) throws IOException {
        try {
            startServer(port);
            Thread.sleep(500);
            startClient(DEFAULT_HOST, port);
        } catch (InterruptedException ex) {
            LOG.error(null, ex);
        }
    }

    /**
     * Start a client, connecting to the server denoted at host and port.
     *
     * @param host  The host name of the server to connect to.
     * @param port  The port number to connect to.
     */
    public static final void startClient(final String host, final int port) {
        final ClientConfig config = new ClientConfig();
        config.setRemotePort(port);
        config.setRemoteHost(host);
        final ClientWindow window = new ClientWindow(config);
        final Client client = new Client(config);
        window.add(client.getPanel());
        window.setVisible(true);
    }

    /**
     * Start dedicated server.
     *
     * @param port The port that clients can connect to
     * @throws IOException when the port cannot be bound
     */
    public static final void startServer(final int port) throws IOException {
        // parse args
        final Game game = GameFactory.makeGame();
        GameFactory.loadGameProperties(game);
        final Server server = new Server(game, port);
        game.start();

    }

    /**
     * Start server with a built-in administration console.
     *
     * @param port The port that clients can connect to
     * @throws IOException when the port cannot be bound
     */
    public static final void startAdminServer(final int port) throws
            IOException {
        // parse args
        final Game game = GameFactory.makeGame();
        GameFactory.loadGameProperties(game);

        final Server server = new Server(game, port);
        game.start();
        final LocustsAdmin admin = new LocustsAdmin(server);
        admin.setVisible(true);

    }
}
